#ifndef MSGQUEUE_HPP
#define MSGQUEUE_HPP

#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

const std::string pathName = "/tmp";
const int pro_id = 0x1314;

const int default_fd = -1;
const int default_size = 1024;

#define GET_MSGQUEUE (IPC_CREAT)
#define CREATE_MSGQUEUE (IPC_CREAT | IPC_EXCL | 0666)

class MsgQueue
{
// 有类型数据块
    struct msgbuf
    {
        long mtype;
        char mtext[default_size];
    };
public:
    MsgQueue(){}
    MsgQueue(int size): _msgfd(default_fd){}
    
    // 创建消息队列
    void Create(int flag)
    {
        // 获取唯一键值
        key_t key = ftok(pathName.c_str(), pro_id);
        if(key == -1)
        {
            std::cerr << "ftok error" << std::endl;
            exit(1);
        }
        // 按照 16 进制打印 键值
        std::cerr << "key: " << key << std::endl;

        _msgfd = msgget(key, flag);
        if(_msgfd == -1)
        {
            std::cerr << "msgget error" << std::endl;
            exit(2);
        }
        std::cout << "Create success: " << _msgfd << std::endl;
    }

    // 发送消息
    void Send(int type, const std::string &text)
    {
        struct msgbuf msg;
        memset(&msg, 0, sizeof(msg));
        msg.mtype = type;
        memcpy(msg.mtext, text.c_str(), text.size());
        // 注意；填长度不能直接写成 sizeof(msg);
        int n = msgsnd(_msgfd, &msg, sizeof(msg.mtext), 0);
        if(n == -1)
        {
            std::cerr << "msgnd error" << std::endl;
            return ;
        }
    }

    // 接收消息：参数设置为输出型参数
    void Recv(int type, std::string &text)
    {
        struct msgbuf msg;
        memset(&msg, 0, sizeof(msg));
        int n = msgrcv(_msgfd, &msg, sizeof(msg.mtext), type, 0);
        if(n == -1)
        {
            std::cerr << "msgrcv error" << std::endl;
            return ;
        }
        msg.mtext[n] = '\0';
        text = msg.mtext; 
    } 

    // 获取消息队列属性
    void GetAttr()
    {
        struct msqid_ds outbuffer;
        int n = msgctl(_msgfd, IPC_STAT, &outbuffer);
        if(n == -1)
        {
            std::cerr << "msgctl error" << std::endl;
            return ;
        }
        std::cout << "outbuffer.msg_perm__key: " << std::hex << outbuffer.msg_perm.__key << std::endl;
    }

    // 删除消息队列
    void Destroy()
    {
        int n = msgctl(_msgfd, IPC_RMID, nullptr);
        if(n == -1)
        {
            std::cerr << "msgctl error" << std::endl;
            exit(3);
        }
        std::cout << "Destroy success"<< std::endl;
    }

    ~MsgQueue()
    {}

private:
    int _msgfd;
};

// 需要定义消息类型
#define MSG_TYPE_CLIENT 1
#define MSG_TYPE_SERVER 2

class Server: public MsgQueue
{
public:
    Server()
    {
        MsgQueue::Create(CREATE_MSGQUEUE);
        std::cout << "server create success" << std::endl;
        MsgQueue::GetAttr();
    }

    ~Server()
    {
        MsgQueue::Destroy();
    }
};

class Client: public MsgQueue
{
public:
    Client()
    {
        MsgQueue::Create(GET_MSGQUEUE);
        std::cout << "client create success" << std::endl;
    }

    ~Client()
    {
        // MsgQueue::Destroy();
    }
};


#endif